package com.cskaoyan.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @Aspect → 指定组件为切面组件
 * @Pointcut → 写一个切入点表达式，并且指定切入点id
 * @Before、@After、@Around、@AfterReturning、@AfterThrowing
 * → 使用不同类型的通知，和切面组件中的方法做关联，和切入点id做关联
 */
@Aspect //不能省略这个@Component注解
@Component
public class CustomAspect {

    // 方法名作为切入点id,@Pointcut注解的value属性就是表达式
    @Pointcut("execution(* com..service..*(..))")
    public void servicePointcut(){}

    //所有通知的方法修饰符都写为public
    // Around通知的方法类似于InvocationHandler的invoke和MethodInterceptor的invoke
    // Around通知的返回值 作为代理对象执行方法的返回值

    //通知注解的value属性 → 1、直接写切入点表达式；2、引用切入点id
    //@Around("servicePointcut()")
    @Around("execution(* com..service..*(..))")
    public Object around(ProceedingJoinPoint joinPoint){
        System.out.println("around的前半部分");
        long start = System.currentTimeMillis();
        Object proceed = null;//执行委托类方法
        // Before通知：jointPoint.proceed执行之前的部分
        try {
            Object[] args = joinPoint.getArgs();
            if ("method2".equals(joinPoint.getSignature().getName())) {
                args[0] = args[0] + "牛皮";
            }
            // 如果修改参数则使用有参的proceed方法，如果使用无参的proceed方法，则使用的是原先的参数
            //proceed = joinPoint.proceed();
            proceed = joinPoint.proceed(args);

            //AfterReturning通知：jointPoint.proceed执行之后的部分，catch之前的部分；proceed就是委托类方法的返回结果
            long end = System.currentTimeMillis();
            System.out.println("around的后半部分");
            System.out.println("方法的执行时间：" + (end - start));
        } catch (Throwable throwable) {
            // AfterThrowing通知：catch住异常
            throwable.printStackTrace();
        } finally {
            // After通知：finally
        }

        return proceed;
    }

    // 除了Around，其他的通知的返回值都写void
    @Before("servicePointcut()")
    public void before(JoinPoint joinPoint) {
        Object proxy = joinPoint.getThis();
        Object target = joinPoint.getTarget();
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        Object[] args = joinPoint.getArgs();

        System.out.println("before通知");

    }

    @After("servicePointcut()")
    public void after() {
        System.out.println("after通知");
    }

    @AfterReturning(value = "servicePointcut()",returning = "result2")
    public void afterReturning(Object result2) {
        System.out.println("afterReturning:" + result2);
    }
    @AfterThrowing(value = "servicePointcut()",throwing = "exception")
    public void afterThrowing(Exception exception) {
        System.out.println("afterThrowing:" + exception.getMessage());
    }
}
